package com.spodrum.balloon;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.Random;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Paint.Style;
import android.graphics.PorterDuff.Mode;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.SoundPool;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class BalloonView extends SurfaceView implements SurfaceHolder.Callback 
{
	private static int MAX_BALLOONS = 20;
	private static int MIN_BALLOONS = 10;
	private static int MAX_LEVEL = 10;
	
    /*
     * State-tracking constants
     */
    public static final int STATE_PAUSE = 1;
    public static final int STATE_READY = 2;
    public static final int STATE_RUNNING = 3;
    public static final int STATE_WIN = 4;
    
    private int state = STATE_READY;
    
	private ArrayList<Balloon> balloons = new ArrayList<Balloon>();
	
	private static final Random RNG = new Random();
	private int[] colours = new int[]{Color.RED, Color.BLUE, Color.YELLOW, Color.WHITE, Color.GREEN};
	
	private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
	private Drawable balloon;
	private Bitmap background;
	private Bitmap balloon_title;
	//private Drawable bronzeMedal, silverMedal, goldMedal;
	private Medal medal;
	private ParticleManager particleManager;
	
	private int minWidth, minHeight, maxWidth, maxHeight;
	private int stage;
	private int popped;	
	
    /** The thread that actually draws the animation */
    private BalloonGameThread thread;
    
    /**
     * Sound
     */
    private MediaPlayer mediaPlayer;
    private SoundPool soundPool;
    
    public BalloonView(Context context, AttributeSet attrs) 
    {
        super(context, attrs);

        // register our interest in hearing about changes to our surface
        SurfaceHolder holder = getHolder();
        holder.addCallback(this);
        
        balloon = context.getResources().getDrawable(R.drawable.balloon_small);
        //bronzeMedal = context.getResources().getDrawable(R.drawable.bronze_medal);
        //silverMedal = context.getResources().getDrawable(R.drawable.silver_medal);
        //goldMedal = context.getResources().getDrawable(R.drawable.gold_medal);
        
        background = BitmapFactory.decodeResource(context.getResources(), R.drawable.background);
        balloon_title = BitmapFactory.decodeResource(context.getResources(), R.drawable.balloon_title);
        
        particleManager = new ParticleManager(context);
        
        paint.setColor(Color.YELLOW);
        paint.setTextSize(32);
        
        maxWidth = balloon.getIntrinsicWidth() / 2;
        maxHeight = balloon.getIntrinsicHeight() / 2;
        minWidth = maxWidth * 3/4;
        minHeight = maxHeight * 3 / 4;
        
        //setup sound
        soundPool = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);
        soundPool.load(context, R.raw.pop1, 1);
        soundPool.load(context, R.raw.pop2, 1);
        soundPool.load(context, R.raw.pop3, 1);
        soundPool.load(context, R.raw.pop4, 1);
        soundPool.load(context, R.raw.pop5, 1);
        soundPool.load(context, R.raw.pop6, 1);
        soundPool.load(context, R.raw.pop7, 1);
        
        mediaPlayer = MediaPlayer.create(context, R.raw.blaydon_races);
        mediaPlayer.setLooping(true);
        
        // create thread only; it's started in surfaceCreated()
        thread = new BalloonGameThread(holder, this);
        
        setFocusable(true);

    }
    
    public void init()
    {
		Balloon balloon = null;
		
		for(int i = 0; i < MAX_BALLOONS; i++ )
		{			
			balloon = new Balloon();
			balloon.setPopped(true);
			
			balloons.add(balloon);
		}
		
		resetBalloons();
		
		Collections.sort(balloons);
    }
    
    public void update()
    {
    	switch(state)
    	{ 
    		case STATE_RUNNING:
    		{
    	    	for(Balloon b:balloons)
    	    	{
    	    		if(!b.isPopped())
    	    			b.update();

    	    		//if the balloon goes off the screen remove it.
    	    		if(b.getY() > getHeight())
    	    		{
    	    			b.setPopped(true);
    	    		}
    	    	}

    	    	if(allBalloonsPopped())
    	    	{
    	    		if(stage == 1 )
    	    		{
    	    			setState(STATE_WIN);
    	    			if(popped >=15)
    	    			{
    	    				medal = new Medal(writeOnMedal(R.drawable.gold_medal, "You Won gold!"), getWidth()/2, getHeight()/2);
    	    			}
    	    			else if(popped >=10)
    	    			{
    	    				medal = new Medal(writeOnMedal(R.drawable.silver_medal, "You Won silver!"), getWidth()/2, getHeight()/2);
    	    			}
    	    			else
    	    			{
    	    				medal = new Medal(writeOnMedal(R.drawable.bronze_medal, "You Won bronze!"), getWidth()/2, getHeight()/2);
    	    			}
    	    		}
    	    		else
    	    		{
    	    			stage++;
    	    			resetBalloons();
    	    		}
    	    	}
    	    	break;
    		}
    		case STATE_WIN:
    		{
    			medal.update();
    			break;
    		}
    	}

    }
    
    private boolean allBalloonsPopped()
    {
		for(Balloon b:balloons)
		{
			if(!b.isPopped())
				return false;
		}
		
    	return true;
    }
    
    public void render(Canvas canvas)
    {
        // Draw the background color. Operations on the Canvas accumulate
        // so this is like clearing the screen. In a real game you can 
    	// put in a background image of course
    	//canvas.drawColor(Color.BLACK);
    	canvas.drawBitmap(background, 0, 0, null);
    	
    	switch(state)
    	{ 
    		case STATE_READY:
    		{
    			canvas.drawBitmap(balloon_title, 0, getHeight()/4 ,null);
    			break;
    		}
	    	case STATE_RUNNING:
	    	{
	    		Iterator<Balloon> itr = balloons.iterator();
	    		while(itr.hasNext())
	    		{
	    			Balloon b = itr.next();
	    			if(!b.isPopped())
	    			{
	    				balloon.setBounds(b.getRect());
	    				balloon.setColorFilter(b.getColour(), Mode.MULTIPLY);
	    				balloon.draw(canvas);
	    			}
	    		}
	
	    		particleManager.doDraw(canvas);
	    		
	    		canvas.drawText("Stage:" + stage + " Popped:" + popped, 25, 32 , paint);
	    		
	    		break;
	    	}
	    	case STATE_WIN:
	    	{
	    		medal.render(canvas);
	    	}
    	}
    	
    	canvas.restore();	
    }
    
	private boolean isOverlap(Balloon balloon) 
	{
		for(Balloon b:balloons)
		{
			if(Rect.intersects(b.getRect(), balloon.getRect()))
			{
				return true;
			}
		}
			
		return false;
	}

	/*
	 * This method initialises the balloons each time its called.
	 */
	private void resetBalloons()
	{
		
		int size = MIN_BALLOONS + stage;
		if(size > balloons.size())
			size = balloons.size();
		
		for(int i=0; i < size; i++)
		{	
			float factor = RNG.nextFloat();
			int rndWidth = minWidth + (int) (factor * maxWidth);
			int rndHeight = minHeight + (int) (factor * maxHeight);
			
			int rndX = RNG.nextInt((int) (getWidth()) );
			int rndY = RNG.nextInt((int) (getHeight()/2) );
			
			if(rndX + rndWidth > getWidth())
			{
				rndX = getWidth() - rndWidth;
			}
			
			
			Balloon balloon = balloons.get(i);
			
			balloon.setColour(Color.rgb(RNG.nextInt(255), RNG.nextInt(255), RNG.nextInt(255)));
			balloon.setX(rndX);
			balloon.setY(rndY*-1);
			balloon.setWidth(rndWidth);
			balloon.setHeight(rndHeight);
			balloon.updateRect();
			
			balloon.setSpeed(new Speed(0, 3 + RNG.nextInt(Math.max(3, 3 + stage))) ) ;
			balloon.setPopped(false);
		}
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) 
	{		
		
        int action = event.getAction();

        if (action == MotionEvent.ACTION_DOWN) 
        {
            return true;

        } 
        else if (action == MotionEvent.ACTION_UP) 
        {
    		if(state == STATE_READY)
    		{
    			setState(STATE_RUNNING);
    			return true;
    		} else if (state == STATE_WIN)
    		{
    			popped = 0;
    			stage = 0;
    			setState (STATE_READY);
    			return true;
    		}
    		
            int x = (int) event.getX();
            int y = (int) event.getY();
            
            ListIterator<Balloon> itr = balloons.listIterator(balloons.size());
            
            while(itr.hasPrevious())
            {
            	Balloon b = itr.previous();
                if( !b.isPopped() && b.getRect().contains(x, y) )
                {
                	b.setPopped(true);
                	particleManager.spawnParticleExplosion(x, y, b.getColour());
                	//soundPool.play(1 + RNG.nextInt(6), 1.0f, 1.0f, 0, 0, 1.0f);
                	
                	popped++;
                    return true;
                }            	
            }
                   
        }
        
        return false;
	}
    
    /**
     * Obligatory method that belong to the:implements SurfaceHolder.Callback
     */
    
    /* Callback invoked when the surface dimensions change. */
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) 
    {
    	background = Bitmap.createScaledBitmap(
                background, width, height, true);
    	
    	particleManager.setSurfaceSize(width, height);
    }

    public Drawable writeOnMedal(int drawableId, String text)
    {

        Bitmap bm = BitmapFactory.decodeResource(getResources(), drawableId).copy(Bitmap.Config.ARGB_8888, true);

        Path mArc;
        RectF oval = new RectF(8, 75, bm.getWidth(), getHeight()/2);
        mArc = new Path();
        mArc.addArc(oval, -140f, 200f);
        
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); 
        paint.setStyle(Style.FILL);  
        paint.setColor(Color.BLACK); 
        paint.setTextSize(26); 
        

        Canvas canvas = new Canvas(bm);
            	 
        canvas.drawTextOnPath("Well Done!", mArc, 0, 0, paint);

        return new BitmapDrawable(getContext().getResources(), bm);
    }
    
    /*
     * Callback invoked when the Surface has been created and is ready to be
     * used.
     */
    public void surfaceCreated(SurfaceHolder holder) 
    {
        thread.setRunning(true);
        thread.start();
        //thread.run();
        background = Bitmap.createScaledBitmap(
                background, getWidth(), getHeight(), true);
        
        int imageRatio = balloon_title.getWidth()/balloon_title.getHeight();
        int screenRatio = getWidth()/getHeight();
        int scaledWidth, scaledHeight;
        
        if(imageRatio <= screenRatio) 
        {
        	 // The scaled size is based on the height
        	 scaledHeight = getHeight();
        	 scaledWidth = scaledHeight * imageRatio;
        } else 
        {
        	 // The scaled size is based on the width
        	 scaledWidth = getWidth();
        	 scaledHeight = scaledWidth / imageRatio;
        }   
        
        balloon_title = Bitmap.createScaledBitmap(balloon_title, scaledWidth, scaledHeight, true);
        
        //mediaPlayer.start();
    }

    /*
     * Callback invoked when the Surface has been destroyed and must no longer
     * be touched. WARNING: after this method returns, the Surface/Canvas must
     * never be touched again!
     */
    public void surfaceDestroyed(SurfaceHolder holder) 
    {
        // we have to tell thread to shut down & wait for it to finish, or else
        // it might touch the Surface after we return and explode
        boolean retry = true;
        thread.setRunning(false);
       //mediaPlayer.stop();
        while (retry) {
            try {
                thread.join();
                retry = false;
            } catch (InterruptedException e) {
            }
        }
    }

	public int getState() {
		return state;
	}

	public void setState(int state) {
		this.state = state;
	}

}
